package dao

import (
	"a-system/domain/entity"
	"strings"
	"sync"

	"xorm.io/builder"
)

var (
	sysMenuDaoTemp *SysMenuDao
	sysMenuDaoOnce sync.Once
)

type SysMenuDao struct{}

func NewSysMenuDao() *SysMenuDao {
	sysMenuDaoOnce.Do(func() {
		sysMenuDaoTemp = &SysMenuDao{}
	})
	return sysMenuDaoTemp
}

// List 列表
func (m *SysMenuDao) List() (rows []entity.SysMenuVo, err error) {
	err = pgCli.Table(&entity.SysMenu{}).Asc("id", "pid", "weigh").Find(&rows)
	if err != nil {
		return
	}
	return rows, err
}

// MenuList 菜单列表
func (m *SysMenuDao) MenuList() (rows []entity.SysMenuVo, err error) {
	err = pgCli.Table(&entity.SysMenu{}).Where("type != 'button'").Asc("id", "pid", "weigh").Find(&rows)
	if err != nil {
		return
	}
	return rows, err
}

// GetmenuIdsByRoleId 根据角色ID查询菜单树信息
func (m *SysMenuDao) GetmenuIdsByRoleId(roleId int64, menuCheckStrictly bool) ([]int64, error) {
	query := pgCli.Table(&entity.SysMenu{}).Cols("sys_menu.id").Join(
		"left",
		"sys_role_menu",
		"sys_menu.id = sys_role_menu.id").Where("sys_role_menu.role_id = ?", roleId)
	if menuCheckStrictly {
		query.NotIn("sys_menu.id", builder.Select("parent_id").From("sys_menu").Join(
			"inner",
			"sys_role_menu",
			"sys_role_menu.id = sys_menu.id").And(builder.Eq{"sys_role_menu.role_id": roleId}))
	}

	var menuIds []int64
	_, err := query.Asc("parent_id").Asc("order_num").Asc("id").FindAndCount(&menuIds)
	return menuIds, err
}

// Get 查
func (m *SysMenuDao) Get(id string) (entity.SysMenuPageVo, error) {
	var v entity.SysMenuPageVo
	_, err := pgCli.Table(&entity.SysMenu{}).ID(id).Get(&v)
	return v, err
}

// Del 删
func (m *SysMenuDao) Del(ids string) (int64, error) {
	return pgCli.In("id", strings.Split(ids, `,`)).Unscoped().Delete(&entity.SysMenu{})
}

// Add 增
func (m *SysMenuDao) Add(args *entity.SysMenuDto) (int64, error) {
	var v entity.SysMenu
	v.Pid = args.Pid
	v.Type = args.Type
	v.Title = args.Title
	v.Name = args.Name
	v.Path = args.Path
	v.Icon = args.Icon
	v.MenuType = args.MenuType
	v.Url = args.Url
	v.Component = args.Component
	v.Keepalive = args.Keepalive
	v.Extend = args.Extend
	v.Weigh = args.Weigh
	v.Status = args.Status
	v.BaseStruct.UpdatedBy = args.UpdatedBy
	return pgCli.InsertOne(&v)
}

// Edit 改
func (m *SysMenuDao) Edit(args *entity.SysMenuDto) (int64, error) {
	var v entity.SysMenu
	v.Pid = args.Pid
	v.Type = args.Type
	v.Title = args.Title
	v.Name = args.Name
	v.Path = args.Path
	v.Icon = args.Icon
	v.MenuType = args.MenuType
	v.Url = args.Url
	v.Component = args.Component
	v.Keepalive = args.Keepalive
	v.Extend = args.Extend
	v.Weigh = args.Weigh
	v.Status = args.Status
	v.BaseStruct.UpdatedBy = args.UpdatedBy
	return pgCli.ID(args.Id).Update(&v)
}

func (m *SysMenuDao) GetMenuAll() ([]entity.SysMenuVo, error) {
	var v []entity.SysMenuVo
	err := pgCli.Table(&entity.SysMenu{}).Find(&v)
	return v, err
}

// FileMenuByRoleIds 通过RoleId获取权限信息
func (m *SysMenuDao) FileMenuByRoleIds(roleIds []int64) ([]*entity.SysMenuPageVo, error) {
	var v []*entity.SysMenuPageVo

	isAdmin := false
	for _, it := range roleIds {
		if it == 1 {
			isAdmin = true
			break
		}
	}
	if isAdmin {
		// 嵌套查询
		err := pgCli.Table(&entity.SysMenu{}).Find(&v)
		return v, err
	}
	// 嵌套查询
	err := pgCli.Table(&entity.SysMenu{}).In("id", builder.Select("id").From("sys_role_menu").Where(builder.In("role_id", roleIds))).Find(&v)
	return v, err
}
